#include "PrecompiledHeaders.h"
#include "TeleportControl.h"
#include "FromString.h"
#include "Ball.h"

TeleportControl::TeleportControl(OgreNewt::World *w)
{
    world = w;
    last_contact_time = 0;
    currently_teleporting = false;
}

TeleportControl::~TeleportControl()
{

}

TeleportControl *TeleportControl::clone()
{
    TeleportControl *tc = new TeleportControl(world);
    tc->teleport_pairs = teleport_pairs;
    return tc;
}

void TeleportControl::reset()
{
    last_contact_time = 0;
}

void TeleportControl::addTeleport(OgreNewt::Body *body, Ogre::SceneNode *n)
{
    Ogre::SceneNode *scene_node = dynamic_cast<Ogre::SceneNode*>(body->getOgreNode());
    if (!scene_node) throw new Ogre::Exception(11001, "Invalid node for teleport - must be scene node", "TeleportControl::addTeleport");
    
    
    Ogre::Node::ChildNodeIterator children = scene_node->getChildIterator();
    Ogre::Vector3 dir_out(0,0,0);
    while( children.hasMoreElements() )
    {
        Ogre::Node *child = children.getNext();
        Ogre::String name = child->getName();
        
        size_t i = name.find("dir");
        if (i != Ogre::String::npos) {
            dir_out = child->getPosition();
            dir_out.normalise();
            break;
        }
    }
    
    Ogre::String id_str = Ogre::any_cast<Ogre::String>(scene_node->getAttachedObject(0)->getUserAny());
    int id;
    from_string<int>(id, id_str.c_str(), std::dec);
    
    TeleportPairMap::iterator it = teleport_pairs.find(id);
    if (it == teleport_pairs.end())
    {
        TeleportPair new_pair;
        new_pair.body_1 = body;
        new_pair.dir_out_1 = dir_out;
        new_pair.body_2 = NULL;
        
        teleport_pairs[id] = new_pair;
    }
    else
    {
        if (it->second.body_2 == NULL)
        {
            it->second.body_2 = body;
            it->second.dir_out_2 = dir_out;
        }
        else
            throw new Ogre::Exception(11002, "Two teleports already exist with id " + id_str, "TeleportControl::addTeleport");
    }
    
    body->setUserData((void*)id);
        
    Ogre::SceneManager *scene_mgr = scene_node->getCreator();
    Ogre::Vector3 ps_pos = scene_node->_getDerivedPosition();
    ps_pos.y += body->getCollision()->getAABB().getHalfSize().y;
    
    Ogre::ParticleSystem *pParticles = scene_mgr->createParticleSystem(scene_node->getName() + "_ps", "teleport");
    scene_mgr->getRootSceneNode()->createChildSceneNode(ps_pos)->attachObject(pParticles);
    	
}

void TeleportControl::finishedTeleporting()
{
    last_contact_time = play_state->getPlayDuration();
    currently_teleporting = false;
}

void TeleportControl::ballCollision(OgreNewt::Body *teleport_body, OgreNewt::Body *ball_body)
{
    Ogre::Real current_time = play_state->getPlayDuration();
    bool ignore = current_time < last_contact_time + 1;
	last_contact_time = current_time;
	
    if (ignore || currently_teleporting) return;
    
    Ball *ball = NULL;
    TeleportPair teleports;
    
    ball = (Ball *)ball_body->getUserData();
    teleports = teleport_pairs[ (int)teleport_body->getUserData() ];
	
    OgreNewt::Body *dest_port = NULL;
	Ogre::Vector3 dir_out;
    if (teleports.body_1 == teleport_body)
    {
        dest_port = teleports.body_2;
        dir_out = teleports.dir_out_2;
    }
    else if (teleports.body_2 == teleport_body)
    {
        dest_port = teleports.body_1;
        dir_out = teleports.dir_out_1;
    }
	    
    if (dest_port)
    {
        Ogre::Vector3 pos; 
        Ogre::Quaternion junk;
        dest_port->getPositionOrientation(pos, junk);
        pos.y += teleport_body->getCollision()->getAABB().getHalfSize().y;
        ball->teleport(pos, dir_out);
        currently_teleporting = true;
    }
    
}
/*

int TeleportControl::userBegin()
{
    return 1;
}

int TeleportControl::userProcess()
{
    Ogre::Real current_time = play_state->getPlayDuration();
    bool ignore = current_time < last_contact_time + 1;
	last_contact_time = current_time;
	
    if (ignore || currently_teleporting) return 1;
    
    OgreNewt::Body *ball_body, *teleport_body;
    Ball *ball = NULL;
    TeleportPair teleports;
	
	
    if (m_body0->getType() % BODY_TYPE_COUNT == BT_BALL)
    {
        ball_body = m_body0;
        teleport_body = m_body1;
    }
    else if (m_body1->getType() % BODY_TYPE_COUNT == BT_BALL)
    {
        ball_body = m_body1;
        teleport_body = m_body0;
    }
    else
        return 1;
	
    ball = (Ball *)ball_body->getUserData();
    teleports = teleport_pairs[ (int)teleport_body->getUserData() ];
	
    OgreNewt::Body *dest_port = NULL;
	Ogre::Vector3 dir_out;
    if (teleports.body_1 == teleport_body)
    {
        dest_port = teleports.body_2;
        dir_out = teleports.dir_out_2;
    }
    else if (teleports.body_2 == teleport_body)
    {
        dest_port = teleports.body_1;
        dir_out = teleports.dir_out_1;
    }
    else
        return 1;
	    
    if (dest_port)
    {
        Ogre::Vector3 pos; 
        Ogre::Quaternion junk;
        dest_port->getPositionOrientation(pos, junk);
        pos.y += teleport_body->getCollision()->getAABB().getHalfSize().y;
        ball->teleport(pos, dir_out);
        currently_teleporting = true;
    }
	return 1;
}*/

